package com.base.cn.platform.os.service.statistics.base;

import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.utils.DateUtils;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.dao.statistics.base.ZStatisticsUserBaseCountDao;
import com.base.cn.platform.os.dao.user.user.CusUserDao;
import com.base.cn.platform.os.entity.statistics.base.StatisticsDateQueryCondition;
import com.base.cn.platform.os.entity.statistics.base.ZStatisticsUserBaseCount;
import com.base.cn.platform.os.entity.statistics.pvuv.ZStatisticsUniqueVisitorCount;
import com.base.cn.platform.os.entity.statistics.ua.ZStatisticsActiveUserCount;
import com.base.cn.platform.os.entity.user.user.CusUser;
import com.base.cn.platform.os.service.statistics.pvuv.ZStatisticsUniqueVisitorCountBiz;
import com.base.cn.platform.os.service.statistics.ua.ZStatisticsActiveUserCountBiz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 基础统计中的用户注册数据统计Biz
 *
 * @author s.li
 * @date 2019/04/18
 */
@Service
public class ZStatisticsUserBaseCountBiz extends BaseBiz<ZStatisticsUserBaseCount, ZStatisticsUserBaseCountDao> {

    private static final String TIME_FORMAT = "yyyy-MM-dd";
    private static final String TIME_FORMAT_H = "yyyy-MM-dd HH";
    @Autowired
    private ZStatisticsActiveUserCountBiz zStatisticsActiveUserCountBiz;
    @Autowired
    private ZStatisticsOrderBaseCountBiz zStatisticsOrderBaseCountBiz;
    @Autowired
    private ZStatisticsUniqueVisitorCountBiz zStatisticsUniqueVisitorCountBiz;
    @Autowired
    private CusUserDao cusUserDao;

    /**
     * 获取用户统计数据
     * @param dateQueryCondition 是查询的时间条件对象
     * @return List<ZStatisticsUserBaseCount>
     */
    public List<ZStatisticsUserBaseCount> queryUserBaseCountList(StatisticsDateQueryCondition dateQueryCondition){
        List<ZStatisticsUserBaseCount> userBaseCountList;
        //时间列表（每天一个元素）
        List<Date> dateList = dateQueryCondition.getDayList();
        //时间类型，1=今日实时，2=近7天（不包含当天），3=近30天（不包含当天），4=自定义（只可选当天之前的时间，且时间跨度不超过12月）
        if(dateQueryCondition.getType()==1 || dateList.size() ==1){
            //获取当前时间对象
            Date nowDate;
            if(dateQueryCondition.getType()==1){
                nowDate =  new Date();
            }else{
                dateQueryCondition.setType(1);
                nowDate = dateList.get(0);
            }
            String nowTime = DateUtils.format(nowDate,TIME_FORMAT);

            ZStatisticsActiveUserCount activeUserCount = new ZStatisticsActiveUserCount();
            activeUserCount.setCountTime(nowDate);

            ZStatisticsActiveUserCount _activeUserCount = zStatisticsActiveUserCountBiz.findOne("countTime = '"+nowTime+"'",null);
            if(_activeUserCount != null){
                activeUserCount.setCountTime(_activeUserCount.getCountTime());
                activeUserCount.setUserCount(_activeUserCount.getUserCount());
            }
            //查询当天的注册量数据
            userBaseCountList = cusUserDao.queryUserOneDayRegCountList(CusUser.class,nowTime);
            //当天的访问量（UV）
            ZStatisticsUniqueVisitorCount uniqueVisitorCount = zStatisticsUniqueVisitorCountBiz.getOneDayUniqueVisitorCount(nowDate);

            //把当前的时间拆解成24个小时
            List<Date> _dateList = DateUtils.getDay24HourList(nowDate);
            //如果有当前有用户注册数据
            if(ObjectUtils.isNotEmpty(userBaseCountList)){//如果有当前有用户注册数据
                //以小时为Key转成Map
                Map<String,ZStatisticsUserBaseCount> userBaseCountMap = userBaseCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT_H),e->e));
                List<ZStatisticsUserBaseCount> newList = new ArrayList<>();
                IntStream.range(0,_dateList.size()).forEach(index->{
                    Date date = _dateList.get(index);
                    String key = DateUtils.format(date,TIME_FORMAT_H);
                    ZStatisticsUserBaseCount userBaseCount = userBaseCountMap.get(key);
                    if(userBaseCount==null){//如果某个小时中没有统计数据，则生成一条默认的记录
                        userBaseCount = new ZStatisticsUserBaseCount();
                        userBaseCount.setCountTime(date);
                        newList.add(userBaseCount);
                    }
                    if(index==0){
                        //设置UV人数
                        userBaseCount.setVisitorCount(uniqueVisitorCount.getRequestCount());
                        //设置活跃用户量
                        userBaseCount.setActivityUserCount(activeUserCount.getUserCount());
                    }
                });
                if(ObjectUtils.isNotEmpty(newList)){
                    userBaseCountList.addAll(newList);
                }
            }else{//如果当前没有用户注册数据，则将自动生成24条默认统计数据
                List<ZStatisticsUserBaseCount> _userBaseCountList = new ArrayList<>();
                IntStream.range(0,_dateList.size()).forEach(index->{
                    Date date = _dateList.get(index);
                    ZStatisticsUserBaseCount userBaseCount = new ZStatisticsUserBaseCount();
                    userBaseCount.setCountTime(date);
                    if(index==0){
                        userBaseCount.setVisitorCount(uniqueVisitorCount.getRequestCount());
                    }
                    _userBaseCountList.add(userBaseCount);
                });
                userBaseCountList = _userBaseCountList;
            }
        }else{//如果不是当天
            //查询当前的统计表
            userBaseCountList = this.find( "countTime in "+ StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT),null,null);
            //如果有统计过
            if(ObjectUtils.isNotEmpty(userBaseCountList)) {
                //以时间（天）为K，转成Map
                Map<String,ZStatisticsUserBaseCount> userBaseCountMap = userBaseCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT),e->e));
                List<Date> conditionDataList = new ArrayList<>();
                //处理时间，查找到没有统计记录的时间段（天）
                dateList.forEach(date->{
                    ZStatisticsUserBaseCount userBaseCount = userBaseCountMap.get(DateUtils.format(date,TIME_FORMAT));
                    if(userBaseCount==null){//某天的统计数据未生成，则把时间记录起来
                        conditionDataList.add(date);
                    }
                });
                if(ObjectUtils.isNotEmpty(conditionDataList)){//如果有未生成的时间统计数据，则去查询并保存
                    List<ZStatisticsUserBaseCount> _userBaseCountList = this.getUserBaseCountList(conditionDataList);
                    if(ObjectUtils.isNotEmpty(_userBaseCountList)){
                        userBaseCountList.addAll(_userBaseCountList);
                    }
                }
            }else{
                //如果没有过统计数据，则查询并生成
                userBaseCountList = this.getUserBaseCountList(dateList);
            }
        }
        if(ObjectUtils.isNotEmpty(userBaseCountList)){
            //重新排序
            Collections.sort(userBaseCountList, new Comparator<ZStatisticsUserBaseCount>() {
                @Override
                public int compare(ZStatisticsUserBaseCount o1, ZStatisticsUserBaseCount o2) {
                    o1.setUpdateTime(null);
                    o2.setUpdateTime(null);
                    o1.setCreateTime(null);
                    o2.setCreateTime(null);
                    return o1.getCountTime().after(o2.getCountTime())? 1:-1;
                }
            });
        }
        return userBaseCountList;
    }

    /**
     * 从订单表中查询统计数据，未把数据保存到统计表中，并且返回数据
     * @param dateList 时间列表
     * @return  List<ZStatisticsUserBaseCount>
     */
    private List<ZStatisticsUserBaseCount> getUserBaseCountList(List<Date> dateList){
        Map<String,String> params = new HashMap<>();
        params.put("timeSql",StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT));
        List<ZStatisticsUserBaseCount> addList = new ArrayList<>();
        //从订单表中统计出新数据列表
        List<ZStatisticsUserBaseCount> userBaseCountList = cusUserDao.queryUserDayRegCountList(CusUser.class,params);

        if(ObjectUtils.isNotEmpty(userBaseCountList)){
            //以时间为Key转成Map
            Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap = this.uniqueVisitorCountMap(dateList);
            //以时间为Key转成Map
            Map<String, ZStatisticsActiveUserCount> activeUserCountMap = this.activeUserCountMap(dateList);

            //以时间为Key转成Map
            Map<String, ZStatisticsUserBaseCount> orderBaseCountMap = userBaseCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT), e->e));
            dateList.forEach(date->{
                String key = DateUtils.format(date,TIME_FORMAT);
                ZStatisticsUserBaseCount userBaseCount = orderBaseCountMap.get(key);
                if(userBaseCount==null){//如果在指定的天中没有统计数据，则生成一条统计数据
                    userBaseCount = new ZStatisticsUserBaseCount();
                    userBaseCount.setCountTime(date);
                    userBaseCountList.add(userBaseCount);
                }
                //设置访问量
                this.setActiveUserCount(activeUserCountMap,key,userBaseCount);
                //设置访问量
                this.setVisitorCount(uniqueVisitorCountMap,key,userBaseCount);
            });
            //把新统计出来的数据保存到统计表中
            addList.addAll(userBaseCountList);
        }else{
            List<ZStatisticsUserBaseCount> _userBaseCountList = new ArrayList<>();
            //以时间为Key转成Map
            Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap = this.uniqueVisitorCountMap(dateList);
            //以时间为Key转成Map
            Map<String,ZStatisticsActiveUserCount> activeUserCountMap = this.activeUserCountMap(dateList);
            //生成没有统计数据记录对象
            dateList.forEach(date->{
                ZStatisticsUserBaseCount userBaseCount = new ZStatisticsUserBaseCount();
                userBaseCount.setCountTime(date);
                String key = DateUtils.format(date,TIME_FORMAT);
                //设置访问量
                this.setActiveUserCount(activeUserCountMap,key,userBaseCount);
                //设置访问量
                this.setVisitorCount(uniqueVisitorCountMap,key,userBaseCount);
                //添加数据到列表中
                _userBaseCountList.add(userBaseCount);
            });
            addList.addAll(_userBaseCountList);
        }
        //数据保存
        if(ObjectUtils.isNotEmpty(addList)){
            this.batchSave(addList);
        }
        return addList;
    }

    /**
     * 查询活跃用户数据Map
     * @param dateList 时间列表
     * @return Map<String, ZStatisticsActiveUserCount>
     */
    private Map<String, ZStatisticsActiveUserCount> activeUserCountMap(List<Date> dateList) {
        //以时间为Key转成Map
        Map<String, ZStatisticsActiveUserCount> activeUserCountMap = new HashMap<>();
        //查询某个时间段内的每天的UV量（访问量）
        List<ZStatisticsActiveUserCount> activeUserCountList = zStatisticsActiveUserCountBiz.find(" countTime in "+StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT),null,null);
        if(ObjectUtils.isNotEmpty(activeUserCountList)){
            activeUserCountMap.putAll(activeUserCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT),e->e)));
        }
        return activeUserCountMap;
    }

    /**
     * 设置访客量
     * @param uniqueVisitorCountMap 访客数据Map
     * @param key 时间Key
     * @param userBaseCount 统计数据对象
     */
    private void setVisitorCount(Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap,String key ,ZStatisticsUserBaseCount userBaseCount){
        if(ObjectUtils.isNotEmpty(uniqueVisitorCountMap) && StringUtils.isNotEmpty(key) && userBaseCount!=null){
            ZStatisticsUniqueVisitorCount uniqueVisitorCount = uniqueVisitorCountMap.get(key);
            if(ObjectUtils.isNotEmpty(uniqueVisitorCount)){//设置访问量
                userBaseCount.setVisitorCount(uniqueVisitorCount.getRequestCount());
            }
        }
    }

    /**
     * 设置活跃用户量
     * @param activeUserCountMap UA用户数据Map
     * @param key 时间KEY
     * @param userBaseCount 订单统计数据
     */
    private void setActiveUserCount(Map<String, ZStatisticsActiveUserCount> activeUserCountMap, String key, ZStatisticsUserBaseCount userBaseCount){
        if(ObjectUtils.isNotEmpty(activeUserCountMap) && StringUtils.isNotEmpty(key) && userBaseCount!=null){
            ZStatisticsActiveUserCount activeUserCount = activeUserCountMap.get(key);
            if(ObjectUtils.isNotEmpty(activeUserCount)){//设置活跃用户量
                userBaseCount.setActivityUserCount(activeUserCount.getUserCount());
            }
        }
    }

    /**
     * 获取某个时间段内的UV数据
     * @param dateList 时间段列表
     * @return Map<String,ZStatisticsUniqueVisitorCount>
     */
    private Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap(List<Date> dateList){
        //以时间为Key转成Map
        Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap = new HashMap<>();
        //查询某个时间段内的每天的UV量（访问量）
        List<ZStatisticsUniqueVisitorCount> uniqueVisitorCountList = zStatisticsUniqueVisitorCountBiz.find(" requestTime in "+StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT),null,null);
        if(ObjectUtils.isNotEmpty(uniqueVisitorCountList)){
            uniqueVisitorCountMap.putAll(uniqueVisitorCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getRequestTime(),TIME_FORMAT),e->e)));
        }
        return uniqueVisitorCountMap;
    }
}
